from jili.core.printlog import print
import pandas as pd
import numpy as np
import pyfinance as pf
from jili.data.db import getdb_client, insert_one,get_calender
from copy import deepcopy
import datetime,os
import matplotlib.pyplot as plt
from statsmodels.stats.diagnostic import acorr_ljungbox
from scipy.stats import linregress
from  functools import partial
from jili.tool import sortdict,dict2str
from jili.report.finance_chart import chart as kline_chart
"""
暂时搁置 库内保存
但是要保证净值返回形成一定的内容
后续增加内容：
1.指定手数与总资金
2.计算仓位与空仓期

持仓类型：
单合约  占比持仓
多合约占比合约
多合约  占比持仓

1.大批量回测  不关心亏损情况，不盈利的不放算例计算过多指标；亏货不值得计算，赚钱的也不要保存net,是否计算多周期收益
2.单个执行，看详细,
3.保存net,orders
"""
cu=None
cu_net=None
cu_signal=None
def savemongo(**kwargs):
    global cu,cu_net,cu_signal
    ip=kwargs["ip"]
    dbname=kwargs.get("db","research")
    cuname=kwargs.get("cu","evaluate_ss")
    auth=kwargs.get("auth","ant:ant")
    db=getdb_client(dbname=dbname,ip=ip,auth=auth)
    cu=db[cuname]
    if "cu_net" in kwargs.keys():
        cu_net=db[kwargs["cu_net"]]
    if "cu_signal" in kwargs.keys():
        cu_signal=db[kwargs["cu_signal"]]
def rrf(d):
    if d.empty:
        return 0
    d=d+1
    d=d.cumprod()
    r=d.tolist()[-1]-1
    return r
def deal_nan2none(d):
    rst={}
    for k,v in d.items():
        if isinstance(v,dict):
            rst[k]=deal_nan2none(v)
        elif isinstance(v,list) or isinstance(v,tuple):
            t=[]
            for i in v:
                if pd.isna(i):
                    t.append(None)
                else:
                    t.append(i)
            rst[k]=t
        else:
            if pd.isna(v):
                rst[k]=None
            else:
                rst[k]=v
    return rst

def get_rrs(rr,flag,isdetail=0):
    rst={}
    t=rr.resample(flag).apply(rrf)
    if len(t)==0:
        r0=0
        r1=0
    else:
        r0=round(100*len(t[t>0])/len(t),2)
        r1=round(100*len(t[t<0])/len(t),2)
    if len(t[t!=0])==0:
        r2=0
    else:
        r2= round(100*len(t[t > 0]) / len(t[t!=0]), 2)
    if isdetail==2:
        t=t.to_dict()
        for k,v in t.items():
            key=k.to_pydatetime()
            rst[key]=float(v)
    return rst,(r0,r1,r2)
bs_reverse={"buy":"sell","sell":"buy","openbuy":"opensell","opensell":"openbuy","closebuy":"closesell","closesell":"closebuy"}
def signals_data_reverse_bs(signals_data):
    signals_data0=deepcopy(signals_data)
    rst=[]
    for i in signals_data0:
        i["action"]=bs_reverse[i["action"]]
        rst.append(i)
    return rst

import math
from scipy.stats import norm, mstats
def trend_test(x, alpha=0.1):
    n = len(x)

    # calculate S
    s = 0
    for k in range(n-1):
        for j in range(k+1, n):
            s += np.sign(x[j] - x[k])

    # calculate the unique data
    unique_x, tp = np.unique(x, return_counts=True)
    g = len(unique_x)

    # calculate the var(s)
    if n == g:  # there is no tie
        var_s = (n*(n-1)*(2*n+5))/18
    else:  # there are some ties in data
        var_s = (n*(n-1)*(2*n+5) - np.sum(tp*(tp-1)*(2*tp+5)))/18

    if s > 0:
        z = (s - 1)/np.sqrt(var_s)
    elif s < 0:
        z = (s + 1)/np.sqrt(var_s)
    else: # s == 0:
        z = 0

    # calculate the p_value
    p = 2*(1-norm.cdf(abs(z)))  # two tail test
    h = abs(z) > norm.ppf(1-alpha/2)

    if (z < 0) and h:
        trend = -1
    elif (z > 0) and h:
        trend = 1
    else:
        trend = 0

    return trend
def performance_orderspos_pl(orders,pos,pricepool,cashin_total=1000000,fee=0.00115,start_date=None,end_date=None,assettype="stock",isdetail=False):
    r = {}
    if orders:
        objs = []
        for i in orders:
            obj = i["obj"]
            if obj not in objs:
                objs.append(obj)
            deltat = i["closetimekey"] - i["opentimekey"]
            i["holddays"] = deltat.days
            if "plr" not in i.keys():
                i["plr"] = (i["sellprice"] - i["buyprice"]) / i["buyprice"]
            if "pl" not in i.keys():
                i["pl"] = (i["sellprice"] - i["buyprice"])*i["qty"]
        ordersd = pd.DataFrame(orders)
        if start_date   is None:
            start_date = ordersd["opentimekey"].min()
        if end_date   is None:
            end_date = ordersd["closetimekey"].max()
        timekey=end_date
        ordersd.sort_values(["plr"], inplace=True)
        r["总盈亏"] = ordersd["pl"].sum()
        r["累计盈亏率"] = r["总盈亏"] / cashin_total
        r["交易股票"] = len(objs)
        r["换手率"] = ordersd["sellamount"].sum() / cashin_total
        r["交易时间"] = [start_date, end_date]
        r["交易笔数"] = len(orders)
        if assettype=="future":
            r["手数"] = int(ordersd["qty"].sum())
            ordersd["tick"] = ordersd["sellprice"] - ordersd["buyprice"]
            r["点数分布"] = ordersd["tick"].quantile([0, .25, .5, .75, 1]).to_dict()
        if "fee" in ordersd.columns:
            r["手续费总额"] = ordersd["fee"].sum()
        r["盈亏分布"] = ordersd["pl"].quantile([0, .25, .5, .75, 1]).to_dict()
        r["总交易额"] = ordersd["buyamount"].sum() + ordersd["sellamount"].sum()
        r["换手率(双向)"] = r["总交易额"] / cashin_total

        pl1 = ordersd[ordersd["pl"] > 0]
        pl0 = ordersd[ordersd["pl"] < 0]
        r["胜率"] = len(pl1) / r["交易笔数"]
        if len(pl0) != 0 and pl0["pl"].sum() != 0 and len(pl1) != 0:
            r["盈亏比"] = (pl1["pl"].sum() / len(pl1)) / (abs(pl0["pl"].sum()) / len(pl0))
            r["亏损"] = {"笔数": len(pl0), "盈亏": pl0["pl"].sum(), "平均每笔赚": pl0["pl"].sum() / len(pl0)}
        else:
            r["盈亏比"] = 0
            r["亏损"] = []
        if len(pl1) != 0:
            r["盈利"] = {"笔数": len(pl1), "盈亏": pl1["pl"].sum(), "平均每笔亏": pl1["pl"].sum() / len(pl1)}
        else:
            r["盈利"] = []
        if isdetail:
            order1 = {
                "总盈亏": pl1["pl"].sum(),
                "累计盈亏率": pl1["pl"].sum() / cashin_total,
                "交易笔数": len(pl1),
                "盈亏分布": pl1["pl"].quantile([0, .25, .5, .75, 1]).to_dict(),
                "盈亏(%)分布": pl1["plr"].quantile([0, .25, .5, .75, 1]).to_dict(),
                "持有天数分布": pl1["holddays"].quantile([0, .25, .5, .75, 1]).to_dict(),
                "最大盈利": pl1["pl"].max(),
                "最小盈利": pl1["pl"].min(),
                "最大盈利(%)": pl1["plr"].max(),
                "最小盈利(%)": pl1["plr"].min(),
                "最大持有天": pl1["holddays"].max(),
                "最小持有天": pl1["holddays"].min(),
            }
            order0 = {
                "总盈亏": pl0["pl"].sum(),
                "累计盈亏率": pl0["pl"].sum() / cashin_total,
                "交易笔数": len(pl0),
                "盈亏分布": pl0["pl"].quantile([0, .25, .5, .75, 1]).to_dict(),
                "盈亏(%)分布": pl0["plr"].quantile([0, .25, .5, .75, 1]).to_dict(),
                "持有天数分布": pl0["holddays"].quantile([0, .25, .5, .75, 1]).to_dict(),
                "最大盈利": pl0["pl"].max(),
                "最小盈利": pl0["pl"].min(),
                "最大盈利(%)": pl0["plr"].max(),
                "最小盈利(%)": pl0["plr"].min(),
                "最大持有天": pl0["holddays"].max(),
                "最小持有天": pl0["holddays"].min(),
            }
            r["盈利单情况"] = order1
            r["亏损单情况"] = order0
            posd = []
            objs0 = []
            for obj, v in pos.items():
                for bs, vv in v.items():
                    if isinstance(vv, list):
                        for j in vv:
                            if j["qty"] > 0:
                                if obj not in objs0:
                                    objs0.append(obj)
                                i = j["detail"][0]
                                p = pricepool[obj]["close"]
                                if bs == "buy":
                                    i["pl"] = i["qty"] * (p * (1 - fee) - i["buyprice"])
                                    i["plr"] = i["pl"] / i["buyamount"]
                                else:
                                    i["pl"] = i["qty"] * (i["sellprice"] - p * (1 + fee))
                                    i["plr"] = i["pl"] / i["sellamount"]
                                deltat = timekey - i["opentimekey"]
                                i["holddays"] = deltat.days
                                posd.append(i)
                    else:
                        if vv["qty"] > 0:
                            if obj not in objs0:
                                objs0.append(obj)
                            for i in vv["detail"]:
                                p = pricepool[obj]["close"]
                                if bs == "buy":
                                    i["pl"] = i["qty"] * (p * (1 - fee) - i["buyprice"])
                                    i["plr"] = i["pl"] / i["buyamount"]
                                else:
                                    i["pl"] = i["qty"] * (i["sellprice"] - p * (1 + fee))
                                    i["plr"] = i["pl"] / i["sellamount"]
                                deltat = timekey - i["opentimekey"]
                                i["holddays"] = deltat.days
                                posd.append(i)
            if posd:
                posdd = pd.DataFrame(posd)
                posdd0 = posdd[posdd["pl"] < 0]
                posdd1 = posdd[posdd["pl"] > 0]
                pos1 = {
                    "未平仓股票数": len(objs0),
                    "总笔数": len(posdd),
                    "浮动盈亏": posdd["pl"].sum(),
                    "浮动盈亏率": posdd["pl"].sum() / cashin_total,
                    "盈利笔数": len(posdd1),
                    "亏损笔数": len(posdd0),
                    "盈亏分布": posdd["pl"].quantile([0, .25, .5, .75, 1]).to_dict(),
                    "盈亏(%)分布": posdd["plr"].quantile([0, .25, .5, .75, 1]).to_dict(),
                    "持有天数分布": posdd["holddays"].quantile([0, .25, .5, .75, 1]).to_dict(),
                    "最大盈利": posdd["pl"].max(),
                    "最小盈利": posdd["pl"].min(),
                    "最大盈利(%)": posdd["plr"].max(),
                    "最小盈利(%)": posdd["plr"].min(),
                    "最大持有天": posdd["holddays"].max(),
                    "最小持有天": posdd["holddays"].min(),
                }
                pos1["胜率"] = len(posdd1) / len(posdd)
                if len(posdd0) != 0 and posdd0["pl"].sum() != 0 and len(
                        posdd1) != 0:  # {"笔数":len(pl1), "盈亏":pl1["pl"].sum(), "平均每笔亏":pl1["pl"].sum() / len(pl1)}
                    pos1["盈亏比"] = (posdd1["pl"].sum() / len(posdd1)) / (abs(posdd0["pl"].sum()) / len(posdd0))
                    pos1["亏损"] = {"笔数": len(posdd0), "盈亏": posdd0["pl"].sum(),
                                  "平均每笔亏": posdd0["pl"].sum() / len(posdd0)}
                else:
                    pos1["盈亏比"] = 0
                    pos1["亏损"] = {}
                if len(posdd1) != 0:
                    pos1["盈利"] = {"笔数": len(posdd1), "盈亏": posdd1["pl"].sum(),
                                  "平均每笔亏": posdd1["pl"].sum() / len(posdd1)}
                else:
                    pos1["盈利"] = {}
                r["持仓单情况"] = pos1
            else:
                pos1 = {
                    "未平仓股票数": 0,
                    "总笔数": 0,
                    "浮动盈亏": 0,
                    "浮动盈亏率": 0,
                    "盈利笔数": 0,
                    "亏损笔数": 0,
                    "盈亏分布": [],
                    "盈亏(%)分布": [],
                    "持有天数分布": [],
                    "最大盈利": None,
                    "最小盈利": None,
                    "最大盈利(%)": None,
                    "最小盈利(%)": None,
                    "最大持有天": None,
                    "最小持有天": None,
                }
                pos1["胜率"] = None
                pos1["盈亏比"] = 0
                pos1["亏损"] = {}
                pos1["盈利"] = {}
    else:
        r["总盈亏"] = 0
        r["累计盈亏率"] = 0
        r["交易股票"] = 0
        r["换手率"] = 0
        r["交易时间"] = []
        r["交易笔数"] = 0
        r["手数"] = 0
        r["手续费总额"] = 0
        r["点数分布"] = {}
        r["盈亏分布"] = {}
        r["总交易额"] = 0
        r["换手率"] = 0
        r["胜率"] = 0
        r["盈亏比"] = 0
        r["亏损"] = 0
        r["盈利"] = 0
        if isdetail:
            r["盈利单情况"] = {}
            r["亏损单情况"] = {}
            r["持仓单情况"] = {}
    return r

def performance_net(plr_d,start_date=None,end_date=None,isdetail=0,pos_rate={},tradedays=None):
    nets = {}
    rst={}
    if start_date   is None:
        ds = list(plr_d.keys())
        ds.sort()
        start_date = ds[0]
        if len(ds) == 1:
            end_date = ds[0]
        else:
            end_date = ds[1]
    if pos_rate:
        maxposrate=max(list(pos_rate.values()))
        rst["最大仓位"]=maxposrate
    nopos = 0
    if tradedays is None:
        tradedays=get_calender
    for d in tradedays(start_date, end_date):
        if d not in plr_d.keys():
            plr_d[d] = 0
            nopos = nopos + 1
        elif d in pos_rate.keys():
            if pos_rate[d]<=0.01:
                nopos = nopos + 1
    rst["无机会占比(%)"] = float(round(100 * nopos / len(plr_d), 1))
    rst["策略占用(%)"] = float(round(100 - rst["无机会占比(%)"], 1))
    rrr = pd.Series(plr_d)
    rrr.sort_index(inplace=True)
    r_w, r_w_r = get_rrs(rrr, "1W", isdetail)
    r_m, r_m_r = get_rrs(rrr, "1M", isdetail)
    r_q, r_q_r = get_rrs(rrr, "1Q", isdetail)
    r_a, r_a_r = get_rrs(rrr, "1A", isdetail)
    if len(rrr)==0:
        rst["日赢占比(%)"] =0
    else:
        rst["日赢占比(%)"] = round(100*len(rrr[rrr > 0]) / len(rrr), 2)
    rst["周赢占比(%)"] = r_w_r[0]
    rst["月赢占比(%)"] = r_m_r[0]
    rst["季赢占比(%)"] = r_q_r[0]
    rst["年赢占比(%)"] = r_a_r[0]
    if len(rrr)==0:
        rst["日亏占比(%)"] =0
    else:
        rst["日亏占比(%)"] = round(100*len(rrr[rrr < 0]) / len(rrr), 2)
    rst["周亏占比(%)"] = r_w_r[1]
    rst["月亏占比(%)"] = r_m_r[1]
    rst["季亏占比(%)"] = r_q_r[1]
    rst["年亏占比(%)"] = r_a_r[1]
    if len(rrr[rrr != 0])==0:
        rst["日赢亏占比(%)"] =0
    else:
        rst["日赢亏占比(%)"] = round(100*len(rrr[rrr > 0]) / len(rrr[rrr != 0]), 2)
    rst["周赢亏占比(%)"] = r_w_r[2]
    rst["月赢亏占比(%)"] = r_m_r[2]
    rst["季赢亏占比(%)"] = r_q_r[2]
    rst["年赢亏占比(%)"] = r_a_r[2]

    rr = pf.TSeries(rrr)
    # rr.sort_index(inplace=True)
    rr.freq = "D"
    rst["年化收益(%)"] = float(round(rr.anlzd_ret() * 100, 2))
    rst["累计收益率"]=rr.cuml_ret()
    rst["总收益(%)"] = float(round(rst["累计收益率"] * 100, 2))
    rst["向上比率(%)"] = float(round(rr.pct_positive()* 100, 2))
    rst["向下比率(%)"] = float(round(rr.pct_negative()* 100, 2))
    #下行标准差
    rst['下行标准差']=round(rr.semi_stdev(),5)
    try:
        rst["年化标准差"] = rr.anlzd_stdev()
        rst["夏普值"] = rr.sharpe_ratio()
    except Exception as e:
        rst["年化标准差"] = 0
        rst["夏普值"] = 10000
    max_draw = rr.max_drawdown()
    if max_draw == 0.0:
        rst["卡玛比率"] = 10000
        rst["最大回撤(%)"] = float(round(max_draw * 100, 2))
    else:
        rst["卡玛比率"] = rr.calmar_ratio()
        rst["最大回撤(%)"] = float(round(max_draw * 100, 2))
    rst["回撤积分"] = rr.drawdown_idx().abs().sum()
    max_draw = float(rr.max_drawdown())
    rst["最深回撤(%)"] = float(round(max_draw*100, 2))
    if max_draw == 0.0:
        rst["最深回撤(天)"] = None
        rst["最深回撤日"] = None
        rst["最深回撤开始"] = None
        rst["最深回撤结束"] = None
        rst["最长回撤(%)"] = 0
        rst["最长回撤(天)"] = 0
        rst["最长回撤日"] = 0
        rst["最长回撤开始"] = None
        rst["最长回撤结束"] = None
        rst["卡玛比率"] = None
        rst["索提诺比率"] = None
        rst["痛苦指数"] = None
    else:
        drawdown = rr.drawdown_idx()
        drawdownd0 = pd.DataFrame(drawdown)
        drawdownd0.columns = ["drawdown"]
        max_draw_date = drawdownd0.loc[drawdownd0["drawdown"] == max_draw].index.to_list()[0]
        drawdownd0.iloc[0, -1] = 0
        drawdownd0.iloc[-1, -1] = 0
        # drawdownd.drop_duplicates(subset=["drawdown"],inplace=True)
        # drawdownd0.loc[:,"d"]=drawdownd0.index
        drawdownd0["d"] = drawdownd0.index
        drawdownd = drawdownd0.loc[drawdownd0["drawdown"] >= 0].copy()
        prei = None
        for i in drawdownd["d"].to_list():
            if prei:
                if prei < max_draw_date and i >= max_draw_date:
                    d0 = i - prei
                    rst["最深回撤(天)"] = d0.days
                    rst["最深回撤日"] = max_draw_date.to_pydatetime()
                    rst["最深回撤开始"] = prei.to_pydatetime()
                    rst["最深回撤结束"] = i.to_pydatetime()
                    break
            prei = i
        # drawdownd.loc[:,"d1"]=drawdownd["d"].diff()
        drawdownd["d1"] = drawdownd["d"].diff()
        macdays = drawdownd["d1"].max()
        dd = drawdownd.loc[drawdownd["d1"] == macdays]["d"].to_list()[0]
        dd = dd.to_pydatetime()
        dd0 = dd - datetime.timedelta(days=macdays.days)
        drawdownd1 = drawdownd0.loc[(drawdownd0["d"] >= dd0) & (drawdownd0["d"] <= dd)]
        min0 = drawdownd1["drawdown"].min()

        rst["最长回撤(%)"] = round(100*min0,2)
        rst["最长回撤(天)"] = macdays.days
        rst["最长回撤日"] = drawdownd1.loc[drawdownd1["drawdown"] == min0]["d"].to_list()[0].to_pydatetime()
        rst["最长回撤期开始"] = dd0
        rst["最长回撤期结束"] = dd
        rst["卡玛比率"] = float(round(rr.calmar_ratio(), 2))
        dd = rr.sortino_ratio(freq=250)
        rst["索提诺比率"] = float(round(dd, 2))

        drawdownd0.loc[drawdownd0["drawdown"] > -0.01, "drawdown"] = 0
        drawdownd = drawdownd0.loc[drawdownd0["drawdown"] >= 0].copy()
        prei = None
        days0 = 0
        total_days = drawdownd0.iloc[-1, -1] - drawdownd0.iloc[0, -1]
        for i in drawdownd["d"].to_list():
            if prei:
                if prei < max_draw_date and i >= max_draw_date:
                    d0 = i - prei
                    days0 = days0 + d0.days
            prei = i
        rst["痛苦指数"] = days0 / total_days.days

    net = rrr + 1
    net = net.cumprod()
    # test1 = acorr_ljungbox(net, lags=[6, 12], return_df=True)
    # test0 = len(test1[test1["lb_pvalue"] > 0.1])
    # if test0 > 0:
    #     test0 = len(test1[test1["lb_pvalue"] > 0.05])
    #     if test0 > 0:
    #         rst["净值序列"] = "随机,0.05置信度下不随机"
    #     else:
    #         rst["净值序列"] = "随机"
    # else:
    #     test0 = trend_test(net, 0.1)
    #     if test0 == 1:
    #         rst["净值序列"] = "增长"
    #     elif test0 == -1:
    #         rst["净值序列"] = "下滑"
    #     else:
    #         rst["净值序列"] = "随机"
    #     if test0 != 0:
    #         x = list(range(1, len(net) + 1))
    #         r = linregress(x, net)
    #         rst["slope"] = r.slope
    #         rst["rvalue"] = r.rvalue
    #         rst["stderr"] = r.stderr
    #         rst["pvalue"] = r.pvalue

    if isdetail == 2:
        nets["周收益"] = r_w
        nets["月收益"] = r_m
        nets["季收益"] = r_q
        nets["年收益"] = r_a
        td = pd.concat([rrr, net], axis=1, ignore_index=True)
        td.columns = ["r", "net"]
        t = td.to_dict("index")
        td = {}
        for k, v in t.items():
            key = k.to_pydatetime()
            td[key] = v
        nets["net"] = td
        nets["return"]=plr_d
        nets["drawdown"]=drawdown
    return rst,nets
def draw_net(net,fig_name):
    name = os.path.basename(fig_name)
    fig = plt.figure(figsize=(16, 9), dpi=80)
    ax1 = fig.add_subplot(111)
    ax1.set_title(name)
    net.plot(ax=ax1, grid=True)
    base_url = os.path.dirname(os.path.abspath(fig_name))
    if not os.path.exists(base_url):
        os.makedirs(base_url)
    fig.savefig(fig_name + ".png")
    plt.close(fig)
def performance_ss(obj,signals_data,fund=0,fee_ticks=2,fig_name=None,start_date=None,end_date=None,isdetail=False,isreverse_bs=False,save_data={},autonet_fig=None,isrightdata=True,k1d_data={}):
    if fund==0 or fund is None:
        return performance_ss_100(obj, signals_data, fee_ticks=fee_ticks, fig_name=fig_name, start_date=start_date, end_date=end_date,k1d_data=k1d_data,
                           isdetail=isdetail, isreverse_bs=isreverse_bs, save_data=save_data, autonet_fig=autonet_fig, isrightdata=isrightdata)
    else:
        return performance_ss_rate(obj, signals_data,fund=fund, fee_ticks=fee_ticks, fig_name=fig_name, start_date=start_date,
                           end_date=end_date,k1d_data=k1d_data,
                           isdetail=isdetail, isreverse_bs=isreverse_bs, save_data=save_data, autonet_fig=autonet_fig,
                           isrightdata=isrightdata)
def performance_ss_rate(obj,signals_data,fund=0,fee_ticks=2,fig_name=None,start_date=None,end_date=None,isdetail=False,isreverse_bs=False,save_data={},autonet_fig=None,isrightdata=False,k1d_data={}):
    pass
def performance_ss_100(obj,signals_data,fee_ticks=2,fig_name=None,start_date=None,end_date=None,isdetail=False,isreverse_bs=False,save_data={},autonet_fig=None,isrightdata=True,k1d_data={}):
    """
    Args:
        obj:pcode,obj都行 获取size  pricetick 计算盈亏用
        signals_data: 信号列表，list 必要信息：timekey,price,action  dict
        qty_mode: 1：一手模式，还是金额限制模式；#暂时实现一手模式  不安金额扩张
        fee_ticks: 税费扣除tick，注意不用的品种不一样
        fig_name:是否出图，None不出，否则输入名字

    Returns:
        按笔，按净值评价结果
    0.信号转订单
    1.订单转净值   无杠杠下的收益与风险
    2.评价订单
    3.评价净值
    """
    rst={}


    #信号转订单
    orders=signal_data2orders(signals_data,k1d_data,isreverse_bs,isrightdata)
    #按笔绩效：总数，盈亏比，胜率，盈利点数，每笔盈亏点数
    if not orders:
        print("没有有效单")
        return None,None
    rst=performance_orders(orders, fee_ticks, obj, start_date=start_date, end_date=end_date)
    step0=True
    if isdetail==0:
        if rst["盈利点数"]<=0:
            step0=False
    if step0:
        # 1.订单转净值 收益率
        plr_d = orders2net(orders,k1d_data,obj)
        rst0,nets,net=performance_net(plr_d,start_date,end_date,isdetail)
        rst.update(rst0)
        rst["obj"] = obj
        rst["start_date"] = start_date
        rst["end_date"] = end_date
        if fig_name:
            isdraw=True
            if autonet_fig is not None and autonet_fig!="":
                if rst["年化收益"]<autonet_fig:
                    isdraw=False
            if isdetail!=0:
                isdraw = True
            if isdraw:
                draw_net(net, fig_name)
    # if cu:
    #     rst.update(save_data)
    #     rst=deal_nan2none(rst)
    #     insert_one(cu,rst)
    # else:
    rst = deal_nan2none(rst)
    # if cu_net:
    #     net0={"net":net}
    #     net0.update(save_data)
    #     insert_one(cu, net0)
    if isdetail==2:
        return rst,nets
    else:
        return rst,None
def performance_mutil_ss(signal_data,mutil_ss_allocation={},fig_name=None,k1d_data={},isdetail=0,isreverse_bs={},isrightdata={},start_date=None,end_date=None):
    """

    Args:
        signal_data:
        mutil_ss_allocation: None:1)抢机会，0，2）顶出，1，可以逐笔评估  主要看胜率笔数
        3）权重配置 权重数据 {}  [] 默认均权 #重在净值评估
        fig_name:

    Returns:

    """
    ss_nets={}
    ss_posrate={}
    rsts={}
    msg_info=str(end_date)[:10]+"日：\n"
    ss_n=0
    drawdowns={}
    if isinstance(mutil_ss_allocation,int):
        if mutil_ss_allocation==0:#1)抢机会
            print("没有实现")
            return None, None
        elif mutil_ss_allocation==1:#长短机会包含
            print("没有实现")
            return None, None
        else:#2）顶出
            print("没有实现")
            return None, None
    else:#3）权重配置 权重数据 {}  []默认均权
        if isinstance(signal_data,list):
            ss_return=[]
            n=0
            for i in signal_data:
                ss_n = n + 1
                msg_info = msg_info + str(ss_n) + "):"
                orders,pos = signal_data2orders2(i, k1d_data, isreverse_bs[n], isrightdata[n])
                n0 = 1
                oo = i[-n0]
                while oo["timekey"] >= end_date:
                    msg_info = msg_info + ",".join([oo["action"], oo["obj"], str(oo["price"]), oo["info"]])
                    n0 = n0 + 1
                    oo = i[-n0]
                if pos:
                    pl = (pos["sellprice"] - pos["buyprice"]) / pos["buyprice"]
                    pl = str(round(pl, 2))
                    if pos["pos"] == "buy":
                        msg_info = msg_info + ",".join(
                            [pos["obj"], "买仓", str(round(pos["buyprice"], 2)), str(pos["opentimekey"])[:10], "盈亏点", pl])
                    else:
                        msg_info = msg_info + ",".join(
                            [pos["obj"], "卖仓", str(round(pos["sellprice"], 2)), str(pos["opentimekey"])[:10], "盈亏点",
                             pl])
                else:
                    msg_info = msg_info + "无持仓"
                rst = performance_orders2(orders, start_date=start_date, end_date=end_date)
                plr_d,pos_rate = orders2net2(orders,k1d_data,start=start_date,end=end_date)
                rst0, nets, net = performance_net(plr_d, start_date=start_date, end_date=end_date,isdetail=isdetail)
                if nets:
                    msg_info0=net_detail2info(nets)
                    msg_info = msg_info + ","+dict2str(msg_info0)
                    drawdowns[str(i)]=nets["drawdown"]
                msg_info = msg_info +"\n"
                rst.update(rst0)
                if isdetail == 2:
                    print("sys",n,rst)
                ss_nets[str(n)]=net
                rsts[str(n)]=rst
                ss_posrate[str(n)]=pos_rate
                ss_return.append(plr_d)
                n=n+1
        else:
            ss_return={}
            for name,i in signal_data.items():
                ss_n=ss_n+1
                msg_info=msg_info+str(ss_n)+")"+name+":"
                orders,pos = signal_data2orders2(i, k1d_data, isreverse_bs[name], isrightdata[name])
                n0=1
                oo=i[-n0]
                while oo["timekey"]>=end_date:
                    msg_info=msg_info+",".join([oo["action"],oo["obj"],str(oo["price"]),oo["info"]])
                    n0=n0+1
                    oo=i[-n0]
                if pos:
                    pl=(pos["sellprice"]-pos["buyprice"])/pos["buyprice"]
                    pl=str(round(pl*100,2))
                    if pos["pos"]=="buy":
                        msg_info=msg_info+",".join([pos["obj"],"买仓",str(round(pos["buyprice"],2)),"->",str(round(pos["sellprice"],2)),str(pos["opentimekey"])[:10],"浮动盈亏",pl])
                    else:
                        msg_info = msg_info+",".join([pos["obj"], "卖仓", str(round(pos["sellprice"],2)),"->",str(round(pos["buyprice"],2)), str(pos["opentimekey"])[:10],"浮动盈亏",pl])
                else:
                    msg_info=msg_info+"无持仓"
                rst = performance_orders2(orders, start_date=start_date, end_date=end_date)
                plr_d,pos_rate = orders2net2(orders,k1d_data,start=start_date,end=end_date)
                rst0, nets, net = performance_net(plr_d, start_date=start_date, end_date=end_date,isdetail=isdetail)
                if nets:
                    msg_info0=net_detail2info(nets)
                    msg_info = msg_info + ","+dict2str(msg_info0)
                    drawdowns[name] = nets["drawdown"]
                msg_info = msg_info +"\n"
                rst.update(rst0)
                if isdetail == 2:
                    print("sys",name,rst)
                ss_nets[name]=net
                ss_posrate[name] = pos_rate
                rsts[name]=rst
                ss_return[name]=plr_d
    rst,net_detail, net=merge_ss_performance(ss_return,mutil_ss_allocation)
    if net_detail:
        ss_n = ss_n + 1
        msg_info = msg_info + str(ss_n) + ")产品:"
        msg_info0 = net_detail2info(net_detail)
        msg_info0["截止日"]=end_date
        msg_info = msg_info + "," + dict2str(msg_info0)
        drawdowns["产品"] = net_detail["drawdown"]
    rst["start_date"]=start_date
    rst["end_date"]=end_date
    rst0={}
    for key in ["年化收益","最深回撤(%)","最长回撤(天)","卡玛比率"]:
        k1 = "对比_" + key
        rst0[k1]={}
        for name, v in rsts.items():
            t=round((rst[key]-v[key])/rst[key],2)
            if t>0:
                info =str(round(v[key]))+"->"+str(round(rst[key]))+"提升"+str(t)
            elif t==0:
                info =str(round(v[key]))+"->"+str(round(rst[key]))+"无变化"
            else:
                info =str(round(v[key]))+"->"+str(round(rst[key]))+"降低"+str(t)
            rst0[k1][name]=(t,info)
    rst0.update(rst)
    print("sys", "产品", rst0)
    if fig_name:
        name = os.path.basename(fig_name)
        fig = plt.figure(figsize=(16, 9), dpi=80)
        ax1 = fig.add_subplot(111)
        ax1.set_title(name)
        net.plot(ax=ax1, grid=True, c='red', label="p")
        for name, net0 in ss_nets.items():
            net0.plot(ax=ax1, grid=True,label=name)
        fig.legend(["p"]+list(ss_nets.keys()),loc="upper left")
        base_url = os.path.dirname(os.path.abspath(fig_name))
        if not os.path.exists(base_url):
            os.makedirs(base_url)
        fig.savefig(fig_name + ".png")
        plt.close(fig)
        posrates={}
        fig = plt.figure(figsize=(16, 9), dpi=80)
        ax1 = fig.add_subplot(111)
        ax1.set_title("p")
        net.plot(ax=ax1, grid=True, c='red', label="p")
        fig.legend(["p"])
        base_url = os.path.dirname(os.path.abspath(fig_name))
        if not os.path.exists(base_url):
            os.makedirs(base_url)
        fig.savefig(fig_name + "产品.png")
        plt.close(fig)



    if isdetail == 2:
        print("sys",msg_info)
        #html
        chart=kline_chart(timekey_strn=10)
        chart.mainchart_return(data=net,name="产品")
        pos_r=merge_ss_posrate(ss_posrate,allocation_ss=mutil_ss_allocation)
        posrates["产品"]=pos_r
        # chart.add_topindex(pos_r,"产品仓位",None)
        for name, net0 in ss_nets.items():
            chart.add_net(data=net0,name=name)
            pos_r=ss_posrate[name]
            posrates[name] = pos_r
            # chart.add_topindex(pos_r, name+"仓位", None)
        if posrates:
            chart.add_sub_chart("line",posrates)
        if drawdowns:
            chart.add_sub_chart("line",drawdowns)
        chart0 = chart.draw("1600px","l3")
        chart0.render(fig_name+"净值.html")
        return rst0,net_detail,msg_info
    else:
        return rst0,None,msg_info

def net_detail2info(net_detail):
    rr = list(net_detail["net"].values())[-1]
    msg_info ={"净值":rr["net"], "当日收益":rr["r"]*100, "当周收益":list(net_detail["周收益"].values())[-1]*100, "当月收益":
         list(net_detail["月收益"].values())[-1]*100, "当季收益":list(net_detail["季收益"].values())[-1]*100, "当年收益":
         list(net_detail["年收益"].values())[-1]*100}
    return msg_info
def merge_ss_posrate(ss_posrate,allocation_ss={}):
    if not allocation_ss:
        n=len(ss_posrate)
        r=1/n
        if isinstance(ss_posrate,list):
            allocation_ss=[]
            for i in range(n):
                allocation_ss.append(r)
        else:
            for name in ss_posrate.keys():
                allocation_ss[name]=r
    rst_r={}
    if isinstance(ss_posrate, list):
        n = len(ss_posrate)
        for d in ss_posrate[0].keys():
            r=0
            for i in range(n):
                r=r+allocation_ss[i]*ss_posrate[i][d]
            rst_r[d]=r
    else:
        names=list(ss_posrate.keys())
        for d in ss_posrate[names[0]].keys():
            r=0
            for i in names:
                r = r + allocation_ss[i] * ss_posrate[i][d]
            rst_r[d] = r
    return rst_r
def merge_ss_performance(ss_return,allocation_ss={},fig_name=None,isdetail=2):
    if not allocation_ss:
        n=len(ss_return)
        r=1/n
        if isinstance(ss_return,list):
            allocation_ss=[]
            for i in range(n):
                allocation_ss.append(r)
        else:
            for name in ss_return.keys():
                allocation_ss[name]=r
    rst_r={}
    if isinstance(ss_return, list):
        n = len(ss_return)
        for d in ss_return[0].keys():
            r=0
            for i in range(n):
                r=r+allocation_ss[i]*ss_return[i][d]
            rst_r[d]=r
    else:
        names=list(ss_return.keys())
        for d in ss_return[names[0]].keys():
            r=0
            for i in names:
                r = r + allocation_ss[i] * ss_return[i][d]
            rst_r[d] = r
    rst, nets, net = performance_net(rst_r,isdetail=isdetail)
    if fig_name:
        draw_net(net, fig_name)
    return rst,nets, net

"""
策略对比
"""
class compare_ss:
    def __init__(self,obj=None,start_date=None,end_date=None):
        self.obj=obj
        self.base_ss=[]
        self.group_compare_ss={}
        self.start_date=start_date
        self.end_date=end_date
    def set_base_ss(self,signals_data,obj=None,start_date=None,end_date=None):
        if obj:
            self.obj=obj
        self.base_ss=signals_data
        if start_date:
            self.start_date=start_date
        if end_date:
            self.end_date=end_date
    def add_compare_ss(self,ss_name,signals_data):
        self.group_compare_ss[ss_name]=signals_data
    def compare(self,obj=None,base_ss=None,group_compare_ss=None,start_date=None,end_date=None,fig_name=None):
        if obj:
            self.obj=obj
        if base_ss:
            self.base_ss=base_ss
        if group_compare_ss:
            self.group_compare_ss=group_compare_ss
        if start_date:
            self.start_date=start_date
        if end_date:
            self.end_date=end_date
        rs={}
        nets={}
        if self.base_ss:
            base_name="base_ss"
        else:
            base_name,self.base_ss=self.group_compare_ss.popitem()
        base_r, basenet = performance_ss(self.obj, self.base_ss, start_date=self.start_date, end_date=self.end_date)
        for ss_name,data in self.group_compare_ss.items():
            r,net=performance_ss(self.obj,data,start_date=base_r["start_date"],end_date=base_r["end_date"])
            for k,v in base_r.items():
                istrue=True
                if isinstance(v,int):
                    istrue=False
                elif isinstance(v,float):
                    istrue=False
                if istrue:
                    continue
                kk="提升_"+k
                vv=0
                if v:
                    if v!=0:
                        vv=round(100*(r[k]-v)/v,2)
                r[kk]=vv
            rs[ss_name]=r
            nets[ss_name]=net
        for k in list(base_r.keys()):
            istrue = True
            v=base_r[k]
            if isinstance(v, int):
                istrue = False
            elif isinstance(v, float):
                istrue = False
            if istrue:
                continue
            kk = "提升_" + k
            base_r[kk]=0
        rs[base_name] = base_r
        nets[base_name] = basenet
        if fig_name:
            name = os.path.basename(fig_name)
            fig = plt.figure(figsize=(16, 9), dpi=80)
            ax1 = fig.add_subplot(111)
            ax1.set_title(name)
            for net in nets.values():
                net.plot(ax=ax1, grid=True)
            fig.legend(list(nets.keys()))
            fig.savefig(fig_name + ".png")
            plt.close(fig)
        return rs,nets
